/*
  LinPVR - Linux Personal Video Recorder
  Copyright (C) 2006 Kamil Pawlowski <kamilpe@gmail.com>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
#include <stdio.h>
#include <string.h>
#include "debug.h"
#include "ogg_dec.h"

int ogg_dec_open(ogg_dec_t *ogg_dec, const char *ogg_path)
{
  ogg_page page;
  ogg_packet packet;
  char *buff;
  int len, streams = 0;

  /* open file */
  ogg_dec->t_serialno = -1;
  ogg_dec->in_file = fopen(ogg_path, "r");
  if (ogg_dec->in_file == NULL)
    return ERR_OPEN;

  /* read all headers */
  ogg_sync_init(&ogg_dec->o_state);  
  while (!feof(ogg_dec->in_file)) {
    /* read page from the file */
    if (ogg_sync_pageout(&ogg_dec->o_state, &page) != 1) {

      buff = ogg_sync_buffer(&ogg_dec->o_state, 4096);
      len = fread(buff, 1, 4096, ogg_dec->in_file);
      ogg_sync_wrote(&ogg_dec->o_state, len);
    } else {
      /* init stream if is not inited */
      if (ogg_page_bos(&page)) {
	if (ogg_dec->t_serialno == -1) {
	  ogg_stream_init(&ogg_dec->to_state, ogg_page_serialno(&page));
	  ogg_stream_pagein(&ogg_dec->to_state, &page);
	  ogg_stream_packetout(&ogg_dec->to_state, &packet);
	  if (!memcmp(packet.packet, "\x80theora", 7)) {
	    theora_info_init(&ogg_dec->t_info);
	    theora_comment_init(&ogg_dec->t_comment);
	    ogg_dec->t_serialno = ogg_page_serialno(&page);
	    streams ++;
	  } else {
	    ogg_stream_clear(&ogg_dec->to_state);
	  }
	}
      }

      /* read and parse data from streams */
      if (ogg_dec->t_serialno == ogg_page_serialno(&page)) {
	ogg_stream_pagein(&ogg_dec->to_state, &page);
	while (ogg_stream_packetout(&ogg_dec->to_state, &packet)>0) {
	  if (theora_packet_isheader(&packet)) {
	    theora_decode_header(&ogg_dec->t_info, &ogg_dec->t_comment, &packet);
	  } else {
	    ogg_stream_packetin(&ogg_dec->to_state, &packet);
	    streams --;
	  }
	}
      }

      if (streams == 0)
	break;
    }
  }

  /* create decode objects */
  if (ogg_dec->t_serialno != -1) {
    theora_decode_init(&ogg_dec->t_state, &ogg_dec->t_info);
  }
}

double ogg_dec_length(ogg_dec_t *ogg_dec)
{
  ogg_page page;
  ogg_packet packet;
  char *buff;
  int len;
  double length=0, max_length=0;

  while (!feof(ogg_dec->in_file)) {
    if (ogg_sync_pageout(&ogg_dec->o_state, &page) != 1) {
      buff = ogg_sync_buffer(&ogg_dec->o_state, 4096);
      len = fread(buff, 1, 4096, ogg_dec->in_file);
      ogg_sync_wrote(&ogg_dec->o_state, len);
    } else if (ogg_dec->t_serialno == ogg_page_serialno(&page)) {
      length = theora_granule_time(&ogg_dec->t_state, ogg_page_granulepos(&page));
      if (length > max_length)
	max_length = length;
    }
  }

  return max_length;
}

void ogg_dec_close(ogg_dec_t *ogg_dec)
{
 if (ogg_dec->t_serialno != -1) {
    theora_info_clear(&ogg_dec->t_info);
    theora_comment_clear(&ogg_dec->t_comment);
    theora_clear(&ogg_dec->t_state);
    ogg_stream_clear(&ogg_dec->to_state);
  }
  fclose(ogg_dec->in_file);
  ogg_sync_clear(&ogg_dec->o_state);
}
